#include "server.h"
#include "wa_define.h"
#include "wa_exception.h"
#include "mongo/bson/bson.h"
#include "mongo/db/json.h"

using namespace mongo;

void Server::main_handle(MongoClient& client, const WAMessage* pmsg){
    state_t     state;
    BSONObj     rv_obj;
    string      rv_str;
    int         type = -1;
    long long   id = -1;
    DBInterface* pdbi;

    int fd = pmsg->fd;
    try{
        BSONObj         obj = fromjson(pmsg->buf);

        type = getRequestType(obj.getStringField(REQUEST_TYPE));
        if(type == REQ_NEWPROJECT){
            try{
                pdbi = new DBInterface(client);
                string token = pdbi->createProject(obj[REQUEST_PARA]["project"].String());
                m_proj_map[token] = pdbi;
                send_result(fd, BSON("token"<<token));
            }catch(WAException& e){
                delete pdbi;
                log.err("Thow WAError: req[%s] error[%s]", (char*)pmsg->buf, e.c_str());
                send_error(fd, e.what());
            }
            return;
        }

        pdbi = getInterface(client, obj["token"].String());
        switch(type){
        case REQ_REGISTER:
            send_result(fd, BSON("_id"<<pdbi->addUser(obj.getField(REQUEST_PARA).Obj())) );
            break;
        case REQ_LOGIN:
            send_result(fd, pdbi->login(obj[REQUEST_PARA]["user"].String(), obj[REQUEST_PARA]["pass"].String()) );
            break;
        case REQ_GETUSER:
            send_result(fd, pdbi->getUser(obj[REQUEST_PARA]["user"].String()));
            break;
        case REQ_MODUSER:
            pdbi->updUser(obj[REQUEST_PARA]["user"].String(), obj.getField(REQUEST_PARA).Obj().removeField("user"));
            send_ok(fd);
            break;
        case REQ_GETFANS:
            send_result(fd, pdbi->getFans(obj[REQUEST_PARA]["user"].String(), obj[REQUEST_PARA]["start"].Int(), obj[REQUEST_PARA]["num"].Int()));
            break;
        case REQ_ADDFOLLOW:
            pdbi->addFollow(obj[REQUEST_PARA]["user"].String(), obj[REQUEST_PARA]["fol"].String());
            send_ok(fd);
            break;
        case REQ_GETFOLLOWS:
            send_result(fd, pdbi->getFollows(obj[REQUEST_PARA]["user"].String(), obj[REQUEST_PARA]["start"].Int(), obj[REQUEST_PARA]["num"].Int()) );
            break;
        case REQ_DELFOLLOW:
            pdbi->delFollow(obj[REQUEST_PARA]["user"].String(), obj[REQUEST_PARA]["fol"].String());
            send_ok(fd);
            break;
        case REQ_ADDTOPIC:
            send_result(fd, BSON("_id"<<pdbi->addTopic(obj.getField(REQUEST_PARA).Obj())) );
            break;
        case REQ_GETTOPIC:
            send_result(fd, pdbi->getTopic(obj[REQUEST_PARA]["_id"].Long()));
            break;
        case REQ_GETTOPICS:
            send_result(fd, pdbi->getTopics(obj[REQUEST_PARA]["user"].String(), obj[REQUEST_PARA]["start"].Int(), obj[REQUEST_PARA]["num"].Int()));
            break;
        case REQ_DELTOPIC:
            break;
        case REQ_ADDPOST:
            break;
        case REQ_GETPOSTS:
            send_result(fd , pdbi->getPosts(obj.getField(REQUEST_PARA).Long()) );
            break;
        case REQ_DELPOST:
            break;
        case REQ_GETNEARUSERS:
            rv_obj = pdbi->getNearUsers(obj[REQUEST_PARA]["x"].Double(), obj[REQUEST_PARA]["y"].Double(), 
                    obj[REQUEST_PARA]["start"].Int(), obj[REQUEST_PARA]["num"].Int());
            send_result(fd, rv_obj);
            break;
        case REQ_GETNEARTOPICS:
            rv_obj = pdbi->getNearTopics(obj[REQUEST_PARA]["x"].Double(), obj[REQUEST_PARA]["y"].Double(), 
                    obj[REQUEST_PARA]["start"].Int(), obj[REQUEST_PARA]["num"].Int());
            send_result(fd, rv_obj);
            break;
        default:
            log.err("REQ TYPE ERR: req[%s] type[%d]", (char*)pmsg->buf, type);
            send_error(fd, "PARA ERROR");
        }
    }
    catch(WAException& e){
        log.err("Thow WAError: req[%s] error[%s]", (char*)pmsg->buf, e.c_str());
        send_error(fd, e.what());
    }
    catch(DBException& e){
        log.err("Thow DBError: req[%s] type[%d] error[%s] code[%d]", (char*)pmsg->buf, type, e.what(), e.getCode());
        send_error(fd, WAException(WA_ERR_DEF, e.getCode()));
    }
}

const static char* _req_string[] = {
    "createproject",
    "register",
    "login",
    "getuser",
    "moduser",
    "getfans",
    "addfollow",
    "getfollows",
    "delfollow",
    "addtopic",
    "gettopic",
    "gettopics",
    "deltopic",
    "addpost",
    "getposts",
    "delpost",
    "getnearusers",
    "getneartopics"
};

int Server::getRequestType(const char* req){
    for(int i=0; i<REQ_NUM; i++){
        if(strcmp(req, _req_string[i])==0){
            return i;
        }
    }
    return -1;
}
